﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Raven.Client;
using System.Net;
using Raven.Client.Document;
using Raven.Client.Indexes;

namespace Crawler.DataAccess
{
    internal static class RavenDBDocumentStoreFactory
    {
        private static readonly Dictionary<string, IDocumentStore> s_DocumentStores = new Dictionary<string, IDocumentStore>();
        private static readonly Dictionary<string, List<Assembly>> s_DocumentStoreIndexAssemblies = new Dictionary<string, List<Assembly>>();

        public static IDocumentStore GetDocumentStore(string documentUrl, ICredentials credentials)
        {
            return GetRegisteredDocumentStore(documentUrl, credentials);
        }

        public static void RegisterDocumentStoreIndexAssembly(string documentUrl, Assembly assembly)
        {
            List<Assembly> assemblies;
            if (!s_DocumentStoreIndexAssemblies.TryGetValue(documentUrl, out assemblies))
            {
                lock (s_DocumentStoreIndexAssemblies)
                {
                    assemblies = new List<Assembly>();
                    assemblies.Add(assembly);
                    s_DocumentStoreIndexAssemblies.Add(documentUrl, assemblies);
                }
            }
            else
            {
                lock (assemblies)
                {
                    assemblies.Add(assembly);
                }  
            }
        }

        private static List<Assembly> GetDocumentStoreIndexAssemblies(string documentUrl)
        {
            List<Assembly> indexAssemblies;
            if (s_DocumentStoreIndexAssemblies.TryGetValue(documentUrl, out indexAssemblies))
            {
                return indexAssemblies;
            }

            return new List<Assembly>(0);
        }

        private static List<Assembly> PopDocumentStoreIndexAssemblies(string documentUrl)
        {
            List<Assembly> indexAssemblies;
            if (s_DocumentStoreIndexAssemblies.TryGetValue(documentUrl, out indexAssemblies))
            {
                lock (s_DocumentStoreIndexAssemblies)
                {
                    s_DocumentStoreIndexAssemblies.Remove(documentUrl);
                    return indexAssemblies;
                } 
            }

            return new List<Assembly>(0);
        }

        private static IDocumentStore GetRegisteredDocumentStore(string documentUrl, ICredentials credentials)
        {
            IDocumentStore documentStore;
            if (!s_DocumentStores.TryGetValue(documentUrl, out documentStore))
            {
                lock (s_DocumentStores)
                {
                    documentStore = RegisterDocumentStore(documentUrl, credentials);
                }
            }

            return documentStore;
        }

        private static IDocumentStore RegisterDocumentStore(string documentUrl, ICredentials credentials)
        {
            IDocumentStore documentStore = new DocumentStore { Url = documentUrl, Credentials = credentials };
            documentStore.Initialize();

            documentStore.Conventions.DocumentKeyGenerator = OttoCommerceDocumentConventions.GetDocumentKeyGenerator(documentStore.Conventions.DocumentKeyGenerator);
            documentStore.Conventions.IdentityPartsSeparator = OttoCommerceDocumentConventions.IdentityPartsSeparator;

            PopDocumentStoreIndexAssemblies(documentUrl).ForEach(x => IndexCreation.CreateIndexes(x, documentStore));

            s_DocumentStores.Add(documentUrl, documentStore);
            return documentStore;
        }
    }
}